<?php
/**
 * Created by PhpStorm.
 * User: jason
 * Date: 2017/11/7
 * Time: 0:09
 */

namespace Home\Service;


use Common\Util\HttpClient;
use Think\Log;

class OrderService
{
    protected $appid;
    protected $mch_id;
    protected $key;

    protected $notify_url;
    public function __construct()
    {
        $this->appid = C('WECHAT.appid');
        $this->mch_id = C('WECHAT.mch_id');
        $this->key = C('WECHAT.key');
        $this->notify_url = C('WECHAT.notify_url');
    }


    public function validateParam($param)
    {
        if(empty($param['id'])) {
            E('id不能为空！');
        }
        if(empty($param['uid'])) {
            E('uid不能为空！');
        }
    }

    /**
     * 生成微信预支付订单
     */
    public function unifiedorder($param, &$outTradeNo)
    {
        //获取用户选择的充值方案
        $coinModel = M('UserCoinCharge');
        $coinCharge = $coinModel->where(array('id'=>$param['id']))->find();
        $totalFee = (float)$coinCharge['discount_price'] * 100;
        $body = '多谱-'.$coinCharge['name'];
        $coin = (int)$coinCharge['amount'] + (int)$coinCharge['additional_coin'];
        $attach = 'coin=' . $coin . '&style=' . $param['style'];
        $deviceInfo = $param['device_info'] ? $param['device_info'] : 'WEB';
        $spbillCreateIp = $_SERVER['REMOTE_ADDR'];
        $outTradeNo = $this->outTradeNo();
        //$_SERVER['REMOTE_ADDR']
        //获取用户openid;
        $userInfo = M('User')->where(array('id'=>$param['uid']))->field('open_id')->find();
        $openid = $userInfo['open_id'];
        $parameters = array(
            'appid' => $this->appid,
            'attach' => $attach,
            'body' => $body,
            'device_info' => $deviceInfo,
            'mch_id' => $this->mch_id,
            'nonce_str' => $this->getNonceStr(),
            'notify_url' => $this->notify_url,
            'out_trade_no' => $outTradeNo,
            'spbill_create_ip' => $spbillCreateIp,
            'total_fee' => $totalFee,
            'trade_type' => 'NATIVE',
        );
        $parameters['sign'] = $this->sign($parameters);
        //记录订单
        $model = M('UserRechargeOrder');
        $data = array(
            'user_id' => $param['uid'],
            'set_id' => $param['id'],
            'detail' => explode('-', $body)[1],
            'out_trade_no' => $parameters['out_trade_no'],
            'total_fee' => (float)$parameters['total_fee'] / 100,
            'create_time' => date('Y-m-d H:i:s', time())
        );
        $model->add($data);

        return $parameters;
    }

    /**
     * 查询微信支付订单状态
     * @param $outTradeNo
     * @return bool
     */
    public function queryWxOrder($outTradeNo)
    {
        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $parameters = [
            'appid' => $this->appid,
            'mch_id' => $this->mch_id,
            'out_trade_no' => $outTradeNo,
            'nonce_str' => $this->getNonceStr(),
        ];
        $parameters['sign'] = $this->sign($parameters);
        //请求订单状态
        $param = arrayToXml($parameters);
        $returnData = HttpClient::post($url, $param);

        $data = xmlToArray($returnData);
        if ($data['return_code'] == 'FAIL') {
            E($data['return_msg']);
        }
        if ($data['result_code'] == 'FAIL') {
            E($data['err_code_des']);
        }
        if ($data['trade_state'] == 'SUCCESS') {
            //更新订单状态
            $result = $this->updateOrder($data);
            if (!$result) {
                E('订单金额异常');
            }
            return true;
        } else {
            E($data['trade_state_desc']);
        }
    }

    /**
     * 查询支付宝支付订单状态
     * @param $outTradeNo
     * @return bool
     */
    public function queryAliOrder($outTradeNo)
    {
        Vendor('alipay.AopSdk');
        $aop = new \AopClient();
        $aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
        $aop->appId = C('ALIPAY.appid');
        $aop->rsaPrivateKey = C('ALIPAY.privateKey');
        $aop->alipayrsaPublicKey = C('ALIPAY.aliPublicKey');
        $aop->signType = 'RSA2';
        $request = new \AlipayTradeQueryRequest();
        $param = json_encode(['out_trade_no' => $outTradeNo]);
        $request->setBizContent($param);
        $result = $aop->execute ( $request);
        $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
        $resultCode = $result->$responseNode->code;
        if(!empty($resultCode)&&$resultCode == 10000){
            //更新订单状态

            return true;
        } else {
            E($result->$responseNode->msg);
        }
    }
    /**
     * 生成微信sign
     * @param $parameters
     * @return string
     */
    public function sign($parameters)
    {
        //step-1 : 按字典序排序参数
        ksort($parameters);
        $stringSignTemp = '';
        foreach ($parameters as $k => $v) {
            $stringSignTemp .= $k . "=" . $v . "&";
        }
        $stringSignTemp = substr($stringSignTemp, 0, strlen($stringSignTemp)-1);
        //step-2 : 在string后加入key
        $stringSignTemp = $stringSignTemp . "&key=" . $this->key;
        //step-3 : md5加密并转为大写
        $sign = mb_strtoupper(md5($stringSignTemp));

        return $sign;
    }

    /**
     * 检验微信预支付订单返回结果是否有误
     * @param $returnData
     * @return mixed
     */
    public function decryptData($returnData)
    {
        //step-1 : 将xml数组转为array
        $data = xmlToArray($returnData);

        //step-2: 检验返回结果
        if ($data['return_code'] == 'FAIL') {
            E($data['return_msg']);
        }
        if ($data['result_code'] == 'FAIL') {
            E($data['err_code_des']);
        } else {
            return $data;
        }
    }


    /**
     * 生成支付宝订单参数
     * @param $param
     */
    public function getBizContent($param)
    {
        if (!$param['id'] || !$param['uid']) {
            return false;
        }
        //获取用户选择的充值方案
        $coinModel = M('UserCoinCharge');
        $coinCharge = $coinModel->where(array('id'=>$param['id']))->find();
        $coinCharge['style'] = $param['style'];
        $totalAmount = (float)$coinCharge['discount_price'];
        $outTradeNo = $param['out_trade_no'];
        $subject = '多谱-'.$coinCharge['name'];
        $parameters = [
            'out_trade_no'    => $outTradeNo,  //商户订单号
            'product_code'    => 'FAST_INSTANT_TRADE_PAY',  //销售产品码,目前仅为FAST_INSTANT_TRADE_PAY
            'total_amount'    => $totalAmount,  //订单总金额，单位为元
            'subject'         => $subject,   //订单标题
            'passback_params' => urlencode(json_encode($coinCharge))  //回传参数
        ];

        //记录订单
        $model = M('UserRechargeOrder');
        $data = array(
            'user_id' => $param['uid'],
            'set_id' => $param['id'],
            'detail' => $coinCharge['name'],
            'out_trade_no' => $outTradeNo,
            'total_fee' => $totalAmount,
            'create_time' => date('Y-m-d H:i:s', time())
        );
        $model->add($data);
        return json_encode($parameters);
    }


    /**
     * 更新微信订单状态
     */
    public function updateOrder($param)
    {
        $map = array(
            'out_trade_no' => $param['out_trade_no'],
        );
        $model = M('UserRechargeOrder');
        $order = $model->where($map)->find();
        if (!$order) {
            return false;
        }
        //验证订单状态
        if ($order['pay_status'] == 1) {
            Log::writeInfo('The order: No.'. json_encode($order['out_trade_no']) . 'is already processed!', 'wxReply');
            return true;
        }
        $order_total_fee = $param['total_fee'] /100;
        if ((int)$order_total_fee != (int)$order['total_fee']) {
            Log::writeInfo('order: No.'. json_encode($order['out_trade_no']) . '\'s total_fee dismatch. pay_fee is '.json_encode($order_total_fee).'.order_fee is '.json_encode($order['total_fee']), 'wxReply');
            return 0;
        }
        Log::writeInfo('order: No.'. json_encode($order['out_trade_no']) . '\'s total_fee match, modify pay_status from 0 to 1', 'wxReply');
        $data = array(
            'pay_status' => 1, //修改订单状态为已支付
            'pay_time' => $param['time_end'],
            'transaction_id' => $param['transaction_id']
        );
        $model->where($map)->save($data);
        //增加用户帐户金币数量
        $coin = intval(substr($param['attach'], 5, strpos($param['attach'], 'style')-6));  //获取金币数
        $style = intval(substr($param['attach'], -1));
        $userMemberService = new UserMemberService();
        $userMemberService->rechargeUserAccount($order['user_id'], $coin, $style);
        //更新用户金币流水
        $userMemberService->updateUserPayment($order['user_id'], $coin, 1, $param['time_end'], 100, $param['out_trade_no']);
        return true;
    }

    /**
     * 处理支付宝支付的异步通知
     * @param $param
     * @return bool
     */
    public function updateAliOrder($param)
    {
        try {
            $outTradeNo = $param['out_trade_no'];
            $model = M('UserRechargeOrder');
            //step-1　验证订单号是否存在
            $order = $model->where(['out_trade_no' => $outTradeNo])->find();
            if (!$order) {
                Log::writeInfo('Not able to find the order. The out_trade_no is: '. $outTradeNo, 'aliPayReply');
                return false;
            }
            //step-2 验证订单是否已处理
            if ($order['pay_status'] == 1) {
                return true;
            }
            //step-3 验证订单金额是否一致
            if ($param['total_amount'] != $order['total_fee']) {
                Log::writeInfo('order: No.'. $order['out_trade_no'] . '\'s total_fee dismatch. Pay_fee is '.$param['total_amount'].'. Order_fee is '.$order['total_fee'], 'aliPayReply');
                return false;
            }
            //step-4 验证appid与帐号appid是否一致
            if ($param['app_id'] != C('ALIPAY.appid')) {
                Log::writeInfo('appid dismatch! Return Appid is \'' . $param['app_id'] . '\'', 'aliPayReply');
                return false;
            }
            //step-5 验证通过 获取支付结果状态
            if ($param['trade_status'] == 'TRADE_SUCCESS' || $param['trade_status'] == 'TRADE_FINISHED') {
                //step-5.1.1 更新订单支付状态
                $data = [
                    'alipay_trade_no' => $param['trade_no'],
                    'pay_status' => 1,
                    'pay_time' => $param['gmt_close']
                ];
                $model->where(['out_trade_no' => $outTradeNo])->save($data);
                //step-5.1.2 增加用户帐户金币数量
                $passbackParam = json_decode(urldecode($param['passback_params']), true); //支付宝原样回传参数
                $userMemberService = new UserMemberService();
                $coin = $passbackParam['amount'] + $passbackParam['additional_coin'];
                $userMemberService->rechargeUserAccount($order['user_id'], $coin, $passbackParam['style']);
                //step-5.1.3  更新用户金币流水
                $userMemberService->updateUserPayment($order['user_id'], $coin, 1, $param['gmt_close'], 100, $param['out_trade_no']);
                return true;
            } elseif($param['trade_status'] == 'TRADE_CLOSED') {
                //step-5.2.1 更新订单支付状态
                $data = [
                    'alipay_trade_no' => $param['trade_no'],
                    'pay_status' => 9, //交易关闭,未付款
                    'pay_time' => $param['gmt_close']
                ];
                $model->where(['out_trade_no' => $outTradeNo])->save($data);
                return true;
            } else {
                Log::writeInfo('trade status error:'. $param['trade_status'], 'aliPayReply');
                return false;
            }
        } catch (\Exception $e) {
            Log::writeInfo('error:' . $e->getMessage(), 'aliPayReply');
            return false;
        }


    }

    /**
     * 产生随机字符串
     */
    private function getNonceStr()
    {
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        $noceStr = "";
        for ($i = 0; $i < 32; $i++) {
            $noceStr .= $chars[mt_rand( 0, strlen( $chars ) - 1 )];
        }
        return $noceStr;
    }

    /**
     * 生成商品订单号
     */
    public function outTradeNo()
    {
        $date = date('YmdHis', time());
        $chars = '0123456789';
        $rand = "";
        for ($i = 0; $i < 6; $i++) {
            $rand .= $chars[mt_rand( 0, strlen( $chars ) - 1 )];
        }
        $outTradeNo = $date . $rand;
        return $outTradeNo;
    }


}